/*
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Autogenerated file -- DO NOT EDIT!

// NOLINTBEGIN(readability-magic-numbers,hicpp-signed-bitwise)

static std::vector<uint8_t> &operator<<(std::vector<uint8_t> &out, Opcode op)
{
    if (static_cast<unsigned>(op) >= <%= Panda.instructions.select(&:prefix).map(&:opcode_idx).min %>) {
        out.push_back(static_cast<uint8_t>(op));
        out.push_back(static_cast<uint8_t>(static_cast<unsigned>(op) >> 8));
    } else {
        out.push_back(static_cast<uint8_t>(op));
    }
    return out;
}

% def get_min(width, is_signed)
%   if width < 8
%       if is_signed
%           return '%d' % ((1 << (width - 1)) - (1 << width))
%       else
%           return '%d' % ((1 << (width - 1)))
%       end
%   else
%       if is_signed
%           return 'std::numeric_limits<int%d_t>::min()' % width
%       else
%           return '%s + 1' % get_max(width / 2, false)
%       end
%   end
% end
%
% def get_max(width, is_signed)
%   if width < 8
%       if is_signed
%           return '%d' % ((1 << (width - 1)) - 1)
%       else
%           return '%d' % ((1 << width) - 1)
%       end
%   else
%       if is_signed
%           return 'std::numeric_limits<int%d_t>::max()' % width
%       else
%           return 'std::numeric_limits<uint%d_t>::max()' % width
%       end
%   end
% end
%
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
%   emitter_name = group.first.emitter_name
%   formats = group.map(&:format)
%
%   if emitter_name == "Jmp"
%       next
%   end
%
%   i = group.first
%
%   if i.format.encoding.empty? # i.operands.empty?
TEST(BytecodeEmitter, <%= emitter_name %>) {
    TestNoneFormat(Opcode::<%= i.opcode.upcase %>, [](BytecodeEmitter* emitter){
        emitter-><%= emitter_name %>();
    });
}

%   elsif i.jcmp? && !i.format.prefixed?
%     group.each do |group_insn|
%       pretty_format = group_insn.format.pretty.upcase
%       opcode = group_insn.opcode.upcase
TEST(BytecodeEmitter, <%= emitter_name %>Bwd_<%= pretty_format %>) {
    JcmpBwd_<%= pretty_format %>(Opcode::<%= opcode %>, [](BytecodeEmitter* emitter, uint8_t reg, const Label &label){
        emitter-><%= emitter_name %>(reg, label);
    });
}

TEST(BytecodeEmitter, <%= emitter_name %>Fwd_<%= pretty_format %>) {
    JcmpFwd_<%= pretty_format %>(Opcode::<%= opcode %>, [](BytecodeEmitter* emitter, uint8_t reg, const Label &label){
        emitter-><%= emitter_name %>(reg, label);
    });
}

%     end
%   elsif i.jcmp? && i.format.prefixed?
%       # nop
%   elsif i.jcmpz?
%     group.each do |group_insn|
%       pretty_format = group_insn.format.pretty.upcase
%       opcode = group_insn.opcode.upcase
TEST(BytecodeEmitter, <%= emitter_name %>_<%= pretty_format %>) {
    Jcmpz_<%= pretty_format %>(Opcode::<%= opcode %>, [](BytecodeEmitter* emitter, const Label &label){
        emitter-><%= emitter_name %>(label);
    });
}
%     end
%   else
%       group.each do |i|
TEST(BytecodeEmitter, <%= emitter_name %>_<%= i.format.pretty.upcase %>) {
%           ops = format_ops(i.format)
%           num_ops = ops.length # i.operands.length()
%           ['min', 'max'].repeated_permutation(num_ops).each do |p|
%               args = []
%               vals = []
%               p.each_with_index do |v, index|
%                   op = ops[index]
%                   is_signed = op.name.start_with?('imm')
%                   arg = v == 'min' ? get_min(op.width, is_signed) : get_max(op.width, is_signed)
%                   args.push(arg)
%                   if op.width <= 8
%                       vals.push(arg)
%                   elsif op.width == 16
%                       vals.push('Split16(%s)' % arg)
%                   elsif op.width == 32
%                       vals.push('Split32(%s)' % arg)
%                   else
%                       vals.push('Split64(%s)' % arg)
%                   end
%               end
%
%               index = 0
%               packed_vals = []
%               while index < num_ops do
%                   if ops[index].width == 4
%                       packed_vals.push('(((static_cast<uint8_t>(%s) & 0xF) << 4) | (static_cast<uint8_t>(%s) & 0xF))' % [vals[index + 1], vals[index]])
%                       index += 2
%                   else
%                       packed_vals.push(vals[index])
%                       index += 1
%                   end
%               end
%
    {
        BytecodeEmitter emitter;
        emitter.<%= emitter_name %>(<%= args.join(', ') %>);
        std::vector<uint8_t> out;
        ASSERT_EQ(BytecodeEmitter::ErrorCode::SUCCESS, emitter.Build(&out));
        std::vector<uint8_t> expected;
        expected << Opcode::<%= i.opcode.upcase %> << <%= packed_vals.join(' << ') %>;
        ASSERT_EQ(expected, out);
    }

%           end
}

%       end
%   end
% end

// NOLINTEND(readability-magic-numbers,hicpp-signed-bitwise)